<template>
  <div class="ai-assistant">
    <el-drawer v-model="open" :with-header="false" :size="drawerSize" direction="rtl" :modal-class="'ai-drawer-modal'">
      <div class="ai-header">
        <div class="title">
          <el-icon class="title-icon"><ChatDotRound /></el-icon>
          <span>智能助手</span>
          <span class="subtitle">AI Assistant</span>
        </div>
        <div class="spacer"></div>
        <el-popconfirm title="确认清空当前会话？" confirm-button-text="清空" cancel-button-text="取消" @confirm="clear">
          <template #reference>
            <el-button size="small" type="warning" :icon="DeleteFilled" plain>清空</el-button>
          </template>
        </el-popconfirm>
        <el-button size="small" type="primary" :loading="loading" @click="send" :icon="ChatDotRound" class="send-on-header" plain>发送</el-button>
      </div>
      <div class="chat-body" ref="scrollRef">
        <transition-group name="msg-fade" tag="div">
          <div v-for="(m, idx) in messages" :key="idx + '-' + m.role + '-' + m.content" class="msg" :class="m.role">
            <div class="avatar" :class="m.role">
              <span v-if="m.role === 'user'">我</span>
              <span v-else>AI</span>
            </div>
            <div class="bubble-wrapper">
              <div class="bubble">{{ m.content }}</div>
              <div class="meta">
                <span class="time">{{ m.time }}</span>
                <el-button class="copy-btn" size="small" text :icon="DocumentCopy" @click="copy(m.content)">复制</el-button>
              </div>
            </div>
          </div>
        </transition-group>
        <div v-if="loading" class="typing">
          <div class="avatar assistant">AI</div>
          <div class="bubble typing-bubble">
            <span class="dot"></span><span class="dot"></span><span class="dot"></span>
          </div>
        </div>
      </div>
      <div class="suggestions" v-if="!loading && messages.length <= 3">
        <el-tag
          v-for="(s, i) in suggestions"
          :key="i"
          class="suggestion"
          effect="plain"
          round
          @click="quickAsk(s)"
        >{{ s }}</el-tag>
      </div>
      <div class="chat-input">
        <el-input
          v-model="input"
          type="textarea"
          :autosize="{ minRows: 2, maxRows: 6 }"
          placeholder="向智能助手提问... (Enter 发送 / Shift+Enter 换行)"
          @keydown="handleKeydown"
        />
        <el-button type="primary" :loading="loading" @click="send" class="btn-send" :icon="ChatDotRound">发送</el-button>
      </div>
    </el-drawer>
    <el-button class="fab" type="primary" circle @click="toggle">
      <el-icon><ChatDotRound /></el-icon>
    </el-button>
    <el-button v-if="showScrollBtn" class="scroll-bottom" circle @click="scrollToBottom" :icon="ArrowDown" />
  </div>
  
</template>

<script setup>
import { ref, watch, nextTick, onMounted, onBeforeUnmount, computed } from 'vue'
import { ChatDotRound, DeleteFilled, DocumentCopy, ArrowDown } from '@element-plus/icons-vue'

const open = ref(false)
const input = ref('')
const loading = ref(false)
const messages = ref([
  { role: 'assistant', content: '你好，我是项目智能助手，可以帮你配置模型、解释界面、生成示例代码等。', time: new Date().toLocaleTimeString() }
])
const suggestions = ref([
  '如何配置 AI 提供方？',
  '帮我解释一下这个页面结构',
  '生成一个示例 API 请求代码',
  '我的请求失败了该如何排查？'
])

const scrollRef = ref(null)
const showScrollBtn = ref(false)
const drawerSize = computed(() => (window.innerWidth <= 920 ? '100%' : '32%'))
watch(messages, async () => {
  await nextTick()
  if (scrollRef.value) {
    scrollRef.value.scrollTop = scrollRef.value.scrollHeight
  }
})

function toggle() {
  open.value = !open.value
}

function clear() {
  messages.value = []
}

async function send() {
  if (!input.value.trim() || loading.value) return
  const userMsg = { role: 'user', content: input.value.trim() }
  messages.value.push(userMsg)
  input.value = ''
  loading.value = true
  try {
    const resp = await fetch('http://localhost:3001/api/ai/chat', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        messages: messages.value.map(m => ({ role: m.role, content: m.content }))
      })
    })
    const text = await resp.text()
    let data
    try {
      data = JSON.parse(text)
    } catch (_) {
      throw new Error(`非JSON响应: ${text.slice(0, 200)}`)
    }
    if (!resp.ok) {
      const msg = (data && data.error) ? data.error : `HTTP ${resp.status}`
      throw new Error(msg)
    }
    if (data && data.reply) {
      messages.value.push({ role: 'assistant', content: data.reply, time: new Date().toLocaleTimeString() })
    } else {
      messages.value.push({ role: 'assistant', content: '抱歉，未获取到有效回复（空返回）。' })
    }
  } catch (e) {
    messages.value.push({ role: 'assistant', content: `请求失败：${e?.message || e}。请确认代理已启动（npm run ai:server），并正确设置环境变量：
AI_PROVIDER=openai 且 OPENAI_API_BASE/OPENAI_API_KEY/OPENAI_MODEL，或 AI_PROVIDER=qianfan 且 BAIDU_API_KEY/BAIDU_SECRET_KEY。` })
  } finally {
    loading.value = false
  }
}

function handleKeydown(e) {
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault()
    send()
  }
}

function copy(text) {
  if (!text) return
  navigator.clipboard?.writeText(text)
}

function quickAsk(s) {
  input.value = s
  send()
}

function onScroll() {
  if (!scrollRef.value) return
  const nearBottom = scrollRef.value.scrollHeight - scrollRef.value.scrollTop - scrollRef.value.clientHeight < 80
  showScrollBtn.value = !nearBottom
}

function scrollToBottom() {
  if (!scrollRef.value) return
  scrollRef.value.scrollTo({ top: scrollRef.value.scrollHeight, behavior: 'smooth' })
}

onMounted(() => {
  if (scrollRef.value) {
    scrollRef.value.addEventListener('scroll', onScroll)
  }
  window.addEventListener('resize', () => {})
})

onBeforeUnmount(() => {
  if (scrollRef.value) {
    scrollRef.value.removeEventListener('scroll', onScroll)
  }
})
</script>

<style scoped>
.ai-assistant {}

/* 抽屉与头部 */
.ai-drawer-modal { backdrop-filter: blur(2px); }
.ai-header {
  display: flex;
  align-items: center;
  padding: 10px 8px 12px 8px;
  border-bottom: 1px solid var(--el-border-color-lighter);
}
.ai-header .title {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-weight: 700;
}
.ai-header .title .title-icon { color: #409eff; }
.ai-header .title .subtitle {
  font-size: 12px;
  color: var(--el-text-color-secondary);
  font-weight: 500;
}
.ai-header .spacer { flex: 1; }
.send-on-header { margin-left: 8px; }

/* 消息区域 */
.chat-body {
  height: calc(100vh - 240px);
  overflow-y: auto;
  padding: 8px 6px 0 6px;
}
.msg { margin: 10px 0; display: flex; gap: 10px; align-items: flex-end; }
.msg.user { flex-direction: row-reverse; }
.avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  flex: 0 0 28px;
  user-select: none;
}
.avatar.user { background: #409eff; color: #fff; }
.avatar.assistant { background: #e6f0ff; color: #409eff; }
.msg.user .avatar { background: #409eff; color: #fff; }
.msg.assistant .avatar { background: #e6f0ff; color: #409eff; }

.bubble {
  max-width: 78%;
  padding: 10px 12px;
  border-radius: 14px;
  line-height: 1.6;
  white-space: pre-wrap;
  box-shadow: 0 4px 14px rgba(0,0,0,0.06);
}
.bubble-wrapper { max-width: 78%; }
.msg.user .bubble-wrapper { align-items: flex-end; display: flex; flex-direction: column; }
.msg.assistant .bubble-wrapper { align-items: flex-start; display: flex; flex-direction: column; }
.meta { display: flex; gap: 10px; align-items: center; margin-top: 6px; opacity: .75; }
.meta .time { font-size: 12px; color: var(--el-text-color-secondary); }
.copy-btn { padding: 0 6px; height: 22px; }
.msg.user .bubble {
  background: linear-gradient(135deg, #409eff, #6eb6ff);
  color: #fff;
  border-top-right-radius: 6px;
  position: relative;
}
.msg.assistant .bubble {
  background: #f6f8fb;
  color: #333;
  border-top-left-radius: 6px;
  position: relative;
}

/* 气泡尾巴 */
.msg.user .bubble::after {
  content: '';
  position: absolute;
  right: -6px;
  top: 10px;
  width: 0; height: 0;
  border-left: 6px solid #6eb6ff;
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  filter: drop-shadow(0 1px 0 rgba(0,0,0,.05));
}
.msg.assistant .bubble::before {
  content: '';
  position: absolute;
  left: -6px;
  top: 10px;
  width: 0; height: 0;
  border-right: 6px solid #f6f8fb;
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  filter: drop-shadow(0 1px 0 rgba(0,0,0,.05));
}

/* 打字中指示器 */
.typing { display: flex; gap: 10px; align-items: center; margin: 10px 0; }
.typing-bubble { display: inline-flex; gap: 6px; align-items: center; }
.dot {
  width: 6px; height: 6px; border-radius: 50%; background: #a6b6d1; display: inline-block;
  animation: blink 1.4s infinite both; opacity: 0.8;
}
.dot:nth-child(2) { animation-delay: .2s; }
.dot:nth-child(3) { animation-delay: .4s; }
@keyframes blink { 0%, 80%, 100% { opacity: .2 } 40% { opacity: 1 } }

/* 输入区 */
.chat-input { display: flex; align-items: flex-end; margin-top: 12px; gap: 8px; }
.btn-send { align-self: center; }

/* 悬浮按钮 */
.fab {
  position: fixed;
  right: 24px;
  bottom: 24px;
  box-shadow: 0 10px 26px rgba(64,158,255,0.35);
  background: linear-gradient(135deg, #409eff, #66b1ff);
  border: none;
}
.fab:hover { filter: brightness(1.05); }

/* 入场动画 */
.msg-fade-enter-active, .msg-fade-leave-active { transition: all .25s ease; }
.msg-fade-enter-from { opacity: 0; transform: translateY(8px); }
.msg-fade-leave-to { opacity: 0; transform: translateY(-8px); }
.scroll-bottom {
  position: fixed;
  right: 28px;
  bottom: 92px;
  box-shadow: 0 10px 26px rgba(64,158,255,0.25);
  background: #fff;
  color: #409eff;
}
</style>


